import tensorflow as tf

class LeNet:

    HEIGHT = 28
    WIDTH = 28
    TOTAL_LABELS = 10
    
    def __init__(self):
        self.input_x_placeholder = tf.placeholder(
            tf.float32, 
            shape=(None, self.HEIGHT, self.WIDTH, 1), 
            name='input_x_placeholder'
        )
        self.input_y_placeholder = tf.placeholder(
            tf.int32, 
            shape=(None, self.TOTAL_LABELS),
            name='input_y_placeholder'
        )
        conv_1 = tf.layers.conv2d(
            inputs=self.input_x_placeholder,
            filters=6,
            kernel_size=[5, 5],
            strides=1,
            padding='same',
            activation=tf.nn.sigmoid
        )
        conv_2 = tf.layers.conv2d(
            inputs=conv_1,
            filters=6,
            kernel_size=[2, 2],
            strides=2,
            padding='valid',
            activation=tf.nn.sigmoid
        )
        conv_3 = tf.layers.conv2d(
            inputs=conv_2,
            filters=16,
            kernel_size=[5, 5],
            strides=1,
            padding='valid',
            activation=tf.nn.sigmoid
        )
        conv_4 = tf.layers.conv2d(
            inputs=conv_3,
            filters=16,
            kernel_size=[2, 2],
            strides=2,
            padding='valid',
            activation=tf.nn.sigmoid
        )
        flatten_1 = tf.layers.flatten(inputs=conv_4)
        fully_1 = tf.contrib.layers.fully_connected(
            inputs=flatten_1,
            num_outputs=120,
            activation_fn=tf.nn.relu
        )
        fully_2 = tf.contrib.layers.fully_connected(
            inputs=fully_1,
            num_outputs=84,
            activation_fn=tf.nn.relu
        )
        dense_1 = tf.layers.dense(
            inputs=fully_2,
            units=10,
            activation=None,
            use_bias=True    
        )
        self.loss = tf.losses.softmax_cross_entropy(
            onehot_labels=self.input_y_placeholder,
            logits=dense_1
        )
        self.predict = tf.argmax(dense_1, axis=1, name='predict')
        self.standard_ans = tf.argmax(self.input_y_placeholder, axis=1)
        self.accuracy = tf.reduce_mean(
            tf.cast(tf.equal(self.standard_ans, self.predict), tf.float32),
            name='accuracy'
        )
        self.train_op = tf.train.AdamOptimizer(learning_rate=0.00146).minimize(self.loss)
        